package pub.gll.libaptprocessor

import com.google.auto.service.AutoService
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import pub.gll.libaptannotation.Destination
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
import javax.annotation.processing.AbstractProcessor
import javax.annotation.processing.Processor
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.Element
import javax.lang.model.element.TypeElement

@AutoService(Processor::class)
class DestinationProcessor : AbstractProcessor() {
    /**
     * 编译器找到我们关心的注解后，会回调这个方法
     * @param set
     * @param roundEnvironment
     * @return
     */
    override fun process(
        set: Set<TypeElement>,
        roundEnvironment: RoundEnvironment
    ): Boolean {

        // 避免多次调用 process
        if (roundEnvironment.processingOver()) {
            return false
        }
        println("$TAG >>> process start ...")
        val rootDir :String? = processingEnv.options["root_project_dir"]

        // 获取所有标记了 @Destination 注解的 类的信息
        val allDestinationElements = roundEnvironment.getElementsAnnotatedWith(
            Destination::class.java
        ) as Set<Element>
        println(
            TAG + " >>> all Destination elements count = "
                    + allDestinationElements.size
        )

        // 当未收集到 @Destination 注解的时候，跳过后续流程
        if (allDestinationElements.isEmpty()) {
            return false
        }

        // 将要自动生成的类的类名
        val className = "RouterMapping_" + System.currentTimeMillis()
        val builder = StringBuilder()
        builder.append("package com.imooc.router.mapping;\n\n")
        builder.append("import java.util.HashMap;\n")
        builder.append("import java.util.Map;\n\n")
        builder.append("public class ").append(className).append(" {\n\n")
        builder.append("    public static Map<String, String> get() {\n\n")
        builder.append("        Map<String, String> mapping = new HashMap<>();\n\n")
        val destinationJsonArray = JsonArray()

        // 遍历所有 @Destination 注解信息，挨个获取详细信息
        for (element in allDestinationElements) {
            val typeElement = element as TypeElement

            // 尝试在当前类上，获取 @Destination 的信息
            val destination = typeElement.getAnnotation(
                Destination::class.java
            ) ?: continue
            val url: String = destination.url
            val description: String = destination.description
            val realPath = typeElement.qualifiedName.toString()
            println("$TAG >>> url = $url")
            println("$TAG >>> description = $description")
            println("$TAG >>> realPath = $realPath")
            builder.append("        ")
                .append("mapping.put(")
                .append("\"" + url + "\"")
                .append(", ")
                .append("\"" + realPath + "\"")
                .append(");\n")
            val item = JsonObject()
            item.addProperty("url", url)
            item.addProperty("description", description)
            item.addProperty("realPath", realPath)
            destinationJsonArray.add(item)
        }
        builder.append("        return mapping;\n")
        builder.append("    }\n")
        builder.append("}\n")
        val mappingFullClassName = "com.imooc.router.mapping.$className"
        println(
            TAG + " >>> mappingFullClassName = "
                    + mappingFullClassName
        )
        println(
            """$TAG >>> class content = 
$builder"""
        )

        // 写入自动生成的类到本地文件中
        try {
            val source = processingEnv.filer
                .createSourceFile(mappingFullClassName)
            val writer = source.openWriter()
            writer.write(builder.toString())
            writer.flush()
            writer.close()
        } catch (ex: Exception) {
            throw RuntimeException("Error while create file", ex)
        }

        // 写入JSON到本地文件中

        // 检测父目录是否存在
        val rootDirFile = rootDir?.let { File(it) }
        if (rootDirFile?.exists() != true) {
            return false
//            throw RuntimeException("root_project_dir not exist!")
        }

        // 创建 router_mapping 子目录
        val routerFileDir = File(rootDirFile, "router_mapping")
        if (!routerFileDir.exists()) {
            routerFileDir.mkdir()
        }
        val mappingFile = File(
            routerFileDir,
            "mapping_" + System.currentTimeMillis() + ".json"
        )

        // 写入json内容
        try {
            val out = BufferedWriter(FileWriter(mappingFile))
            val jsonStr = destinationJsonArray.toString()
            out.write(jsonStr)
            out.flush()
            out.close()
        } catch (throwable: Throwable) {
            throw RuntimeException("Error while writing json", throwable)
        }
        println(TAG + " >>> process finish.")
        return false
    }

    /**
     * 告诉编译器，当前处理器支持的注解类型
     * @return
     */
    override fun getSupportedAnnotationTypes(): Set<String> {
        return setOf(
            Destination::class.java.canonicalName
        )
    }

    companion object {
        private const val TAG = "DestinationProcessor"
    }
}